#pragma once
#include "LineEntity.h"
#include "MarkerMgr.h"

class RoadMgr : protected IEntityMgr {
public:
	static RoadMgr* get() {
		static auto instance = new RoadMgr;
		return instance;
	}

	/**@brief called per frame, at rendering thread */
	void updateEntities() override {
		bool hasNewData = Cache::useNewlyRcvdLines();

		Global::updateDashedVOffset(Cache::zhicheArg().speed);

		const auto& allArgMap = Cache::lineArgMap();
		for (const auto& kv : allArgMap) {
			const auto& arg = kv.value;
			auto tag = arg.tag;
			Cache::increaseUpdateFrameCnt(tag);
			if (!arg.identified) {/**@deprecated currently not used*/
				removeLineAndGlobalCache(tag);
				continue;
			}
			if (hasNewData)
				updateLine(tag);
		}
		MarkerMgr::get()->update(MarkerType::RoadBg);

		clearExpiredLines();
	}

	void clear() override {
		auto lineArgMap = Cache::lineArgMap();
		for (const auto& kv : lineArgMap)
			removeLineAndGlobalCache(kv.value.tag);
		MarkerMgr::get()->remove(MarkerType::RoadBg);
	}

private:
	RoadMgr() = default;

	void updateLine(LineTag tag) {
		removeLine(tag);
		addLine(tag);
	}

	void addLine(LineTag tag) {
		auto line = new LineEntity(tag);
		m_lineMap.insert(tag, line);
		Scene::add(line);
	}

	void removeLine(LineTag tag) {
		Scene::remove(m_lineMap.take(tag));
	}

	/**
	 *@important be careful: do not remove the global-cached line-datas too early!
	 * because [in a same frame], many other place have to rely on the global-cached line-datas!
	 */
	void removeLineAndGlobalCache(LineTag tag) {
		removeLine(tag);
		Cache::removeLine(tag);
	}

	void clearExpiredLines() {
		const auto ExpireUpdateCnt = Config::Mechanism_ExpireUpdateCnt;
		const auto ExpireFrameCnt = Config::Mechanism_ExpireFrameCnt;
		const auto lineArgMap = Cache::lineArgMap();
		for (const auto& kv : lineArgMap) {
			const auto& arg = kv.value;
			if (arg.updateCnt >= ExpireUpdateCnt || arg.updateFrameCnt >= ExpireFrameCnt)
				removeLineAndGlobalCache(arg.tag);
		}
	}

	CMap<LineTag, LineEntity*> m_lineMap;
};